package org.yzh.web.mp.service.impl;


import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.iov.car.taos.entity.TaosLocation;
import jodd.util.StringUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.yzh.protocol.commons.transform.AttributeKey;
import org.yzh.protocol.commons.transform.attribute.AlarmADAS;
import org.yzh.protocol.commons.transform.attribute.AlarmCrashCustomer;
import org.yzh.protocol.commons.transform.attribute.AlarmDSM;
import org.yzh.protocol.t808.T0200;
import org.yzh.web.model.consts.SysConst;
import org.yzh.web.mp.entity.*;
import org.yzh.web.mp.mapper.TaosLocationMapper;
import org.yzh.web.mp.service.*;
import org.yzh.web.util.OtherApiUtil;
import org.yzh.web.util.gps.GPS;
import org.yzh.web.util.gps.GPSConverterUtils;
import org.yzh.web.util.gps.LbsAmapHelper;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author nick
 * @description td位置数据Service实现类
 * @date 2022/3/8
 **/
@Service
@AllArgsConstructor
@Slf4j
public class TaosLocationServiceImpl extends ServiceImpl<TaosLocationMapper, Location> implements TaosLocationService {


    private final TaosLocationMapper locationMapper;

    // td 6465报警
    private final TaosAlarm64Service alarm64Service;
    private final TaosAlarm65Service alarm65Service;

    // 6465 报警
    private final AlarmSimpleAlarm64Service alarmSimpleAlarm64Service;
    private final AlarmSimpleAlarm65Service alarmSimpleAlarm65Service;

    // 80 报警
    private final AlarmAlarm80Service alarm80Service;

    private final RedissonClient redissonClient;

    // 中国经纬度范围
    private static final BigDecimal MIN_LONGITUDE = BigDecimal.valueOf(73.66);
    private static final BigDecimal MAX_LONGITUDE = BigDecimal.valueOf(135.08);
    private static final BigDecimal MIN_LATITUDE = BigDecimal.valueOf(3.86);
    private static final BigDecimal MAX_LATITUDE = BigDecimal.valueOf(53.55);

    @Override
    public Boolean insert(Location model) {
        return locationMapper.insertOne(model) > 0;
    }


    @Override
    public void insertT0200List(List<T0200> list) {
        // 1.0 数据初始化
        LocalDate nowDate = LocalDate.now();

        // 2.0 插入位置数据
        list = list.stream().filter(f -> StrUtil.isNotBlank(f.getClientId())
                && f.getDeviceTime().isBefore(LocalDateTime.of(nowDate.plusDays(1), LocalTime.MAX))
        ).collect(Collectors.toList());

        if (!list.isEmpty()) {
            for (T0200 item : list) {
                this.processLocationData(item);
            }
        }

        // 3.0 64,65报警处理
        List<AlarmSimpleAlarm64> listAlarmSimpleAlarm64 = new ArrayList<>();
        List<AlarmSimpleAlarm65> listAlarmSimpleAlarm65 = new ArrayList<>();
        list.forEach(item -> {
            // 高级驾驶辅助系统报警
            if (item.getAttributes().get(SysConst.ATTRIBUTE_ADAS_INDEX) != null) {
                listAlarmSimpleAlarm64.add(this.createAlarmSimpleAlarm64FromItem(item));
            }
            //驾驶员状态监测
            if (item.getAttributes().get(SysConst.ATTRIBUTE_DMS_INDEX) != null) {
                // 65报警
                listAlarmSimpleAlarm65.add(this.createAlarmSimpleAlarm65FromItem(item));
            }

            // 碰撞报警
            // 打印 log.error打印 item.getAttributes().get(128)
            // 打印 log.error打印 item.getAttributes().get(128)
            log.error("碰撞报警数据：{}", item.getAttributes().get(128));

            if (item.getAttributes().get(128) != null) {

                AlarmCrashCustomer alarmCrashCustomer = (AlarmCrashCustomer) item.getAttributes().get(128);

                this.processAlarm80(item, alarmCrashCustomer);

            }
        });

        // 3.1 报警批量插入mysql
//        if (!listAlarmSimpleAlarm64.isEmpty()) {
//            alarmSimpleAlarm64Service.saveBatch(listAlarmSimpleAlarm64);
//        }
//        if (!listAlarmSimpleAlarm65.isEmpty()) {
//            alarmSimpleAlarm65Service.saveBatch(listAlarmSimpleAlarm65);
//        }

    }

    private void processAlarm80(T0200 item, AlarmCrashCustomer alarmCrashCustomer) {
        // alarmCrashCustomer 插入到 alarm_alarm80
        AlarmAlarm80 alarm80 = new AlarmAlarm80();
        alarm80.setId(IdUtil.getSnowflakeNextId());
        alarm80.setVehicleId(item.getClientId());
        alarm80.setFlag(alarmCrashCustomer.getState());
        alarm80.setAlarmType(alarmCrashCustomer.getType());
        alarm80.setSpeed(alarmCrashCustomer.getSpeed());
        alarm80.setLongitude(BigDecimal.valueOf(item.getLongitude() / 1000000.0));
        alarm80.setLatitude(BigDecimal.valueOf(item.getLatitude() / 1000000.0));
        alarm80.setVehicleStatus(item.getStatusBit());
        alarm80.setAlarmTime(item.getDeviceTime());
        alarm80.setNote("");
        alarm80.setVersion(0);
        alarm80.setCreateDept(0L);
        alarm80.setCreateTime(item.getDeviceTime());
        alarm80.setCreateBy(0L);
        alarm80.setUpdateTime(item.getDeviceTime());
        alarm80.setUpdateBy(0L);
        alarm80.setDelFlag(0);
        alarm80Service.save(alarm80);

        // 传递第三方请求接口
        // String appId, String sim, String longitude, String latitude,
        //                                      int type, String address, String time, String note,
        //                                      List<Map<String, Object>> mediaList

        GPS gps = GPSConverterUtils.gps84_To_Gcj02(alarm80.getLatitude().doubleValue(), alarm80.getLongitude().doubleValue());
        String address = LbsAmapHelper.getAddressByGps(gps.getLon() + "," + gps.getLat());
        String strId = Convert.toStr(alarm80.getId());
        String body = OtherApiUtil.sendAlarmInfo(strId,
                "10001",
                item.getClientId(),
                Convert.toStr(item.getLongitude() / 1000000.0),
                Convert.toStr(item.getLatitude() / 1000000.0),
                alarmCrashCustomer.getType(),
                address,
                item.getDeviceTime().toString(),
                "",
                null);



        log.info("碰撞报警第三方接口返回：{}", body);

        // 解析第三方接口返回的JSON数据
        if (StringUtil.isNotEmpty(body)) {
            try {
                cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(body);
                Integer code = jsonObject.getInt("Code");
                // 当Code为1时，解析出Data并更新到数据库
                if (code != null && code == 0) {
                    String data = jsonObject.getStr("Data");
                    if (StrUtil.isNotEmpty(data)) {
                        // 更新alarm80的note字段或其他合适字段来存储Data值
                        alarm80.setNote(data);
                        // 更新到数据库
                        alarm80Service.updateById(alarm80);
                        log.info("成功更新报警数据ID: {} 的Data值: {}", alarm80.getId(), data);
                    }
                }
            } catch (Exception e) {
                log.error("解析第三方接口返回数据失败: {}", e.getMessage());
            }
        }



    }


    /**
     * 处理位置信息
     *
     * @param item T0200位置数据实体
     */
    private void processLocationData(T0200 item) {
        // 0.0 基础数据赋值
        int speed = item.getSpeed() / 10;
        String vehicleId = item.getClientId();
        double oil = 0D;
        double mileage = 0D;
        // mileage 报错的话，赋值为0
        try {
            mileage = (double) Convert.toInt(item.getAttributes().get(AttributeKey.Mileage)) / 10;
        } catch (Exception e) {
            mileage = 0D;
        }
        int warningMark = item.getWarnBit();
        int height = item.getAltitude();
        BigDecimal longitude = BigDecimal.valueOf(item.getLongitude() / 1000000.0);
        BigDecimal latitude = BigDecimal.valueOf(item.getLatitude() / 1000000.0);
        int status = item.getStatusBit();
        int orientation = item.getDirection();
        long extStatus = 0L;

        // 0.1 写入时序数据库
        // 如果经纬度不在中国，则不处理
        if (!this.isInChina(latitude.doubleValue(), longitude.doubleValue())) {
            return;
        }
        Location location = new Location();
        location.setTime(item.getDeviceTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        location.setVehicleId(vehicleId);
        location.setStatus(status);
        location.setExtStatus(Convert.toInt(extStatus));
        location.setLongitude(longitude);
        location.setLatitude(latitude);
        location.setSpeed(speed);
        location.setHigh(height);
        location.setOrientation(orientation);
        location.setMileage(mileage);
        location.setOil(oil);
        location.setAddTime(System.currentTimeMillis());
        location.setFlag(0);
        location.setWarningMark(warningMark);
        location.setCid(vehicleId);

        try {
            this.insert(location);
            // 通过redis写入缓存Map
            RMap<String, TaosLocation> redisMap = redissonClient.getMap("taos:location:last:map");
            redisMap.put(location.getVehicleId(), location.toEntityLocation());
        } catch (Exception ex) {
            log.error(ex.toString());
        }
    }


    /**
     * 判断给定的经纬度是否在中国范围内
     *
     * @param latitude  纬度
     * @param longitude 经度
     * @return 如果在范围内返回 true，否则返回 false
     */
    private static boolean isInChina(double latitude, double longitude) {
        BigDecimal lat = BigDecimal.valueOf(latitude);
        BigDecimal lon = BigDecimal.valueOf(longitude);

        return lon.compareTo(MIN_LONGITUDE) >= 0 && lon.compareTo(MAX_LONGITUDE) <= 0
                && lat.compareTo(MIN_LATITUDE) >= 0 && lat.compareTo(MAX_LATITUDE) <= 0;
    }


    /**
     * 65报警实体创建和Td插入
     *
     * @param item T0200位置数据实体
     * @return AlarmSimpleAlarm65
     */
    private AlarmSimpleAlarm65 createAlarmSimpleAlarm65FromItem(T0200 item) {
        String vehicleId = item.getClientId();

        AlarmDSM alarmDsm = (AlarmDSM) item.getAttributes().get(101);

        AlarmSimpleAlarm65 alarmSimpleAlarm65 = this.populateAlarmSimpleFields(vehicleId, alarmDsm.getType(), alarmDsm.getLevel(), alarmDsm.getId(),
                alarmDsm.getFileTotal(), alarmDsm.getDateTime(),
                alarmDsm.getLongitude() / 1000000.0, alarmDsm.getLatitude() / 1000000.0,
                new AlarmSimpleAlarm65());

        // TD 65报警
        alarm65Service.insertAlarm65(vehicleId, alarmDsm);

        return alarmSimpleAlarm65;
    }


    /**
     * 64报警实体创建和Td插入
     *
     * @param item T0200位置数据实体
     * @return AlarmSimpleAlarm64
     */
    private AlarmSimpleAlarm64 createAlarmSimpleAlarm64FromItem(T0200 item) {
        String vehicleId = item.getClientId();
        AlarmADAS alarmAdas = (AlarmADAS) item.getAttributes().get(100);

        AlarmSimpleAlarm64 alarmSimpleAlarm64 = this.populateAlarmSimpleFields(vehicleId, alarmAdas.getType(), alarmAdas.getLevel(), alarmAdas.getId(),
                alarmAdas.getFileTotal(), alarmAdas.getDateTime(),
                alarmAdas.getLongitude() / 1000000.0, alarmAdas.getLatitude() / 1000000.0,
                new AlarmSimpleAlarm64());

        // TD 64报警
        alarm64Service.insertAlarm64(vehicleId, alarmAdas);

        return alarmSimpleAlarm64;
    }

    /**
     * 填充报警Simple实体
     *
     * @param vehicleId        车辆id
     * @param eventType        事件类型
     * @param alarmLevel       报警等级
     * @param alarmId          报警id
     * @param attachments      附件
     * @param time             报警时间
     * @param longitude        经度
     * @param latitude         纬度
     * @param alarmSimpleAlarm 报警实体
     * @param <T>              报警实体
     * @return 报警实体
     **/
    private <T extends AlarmSimpleAlarmBase> T populateAlarmSimpleFields(String vehicleId, Integer eventType,
                                                                         Integer alarmLevel, Long alarmId,
                                                                         Integer attachments, LocalDateTime time,
                                                                         Double longitude, Double latitude,
                                                                         T alarmSimpleAlarm) {
        alarmSimpleAlarm.setId(IdUtil.getSnowflakeNextId());
        alarmSimpleAlarm.setVehicleId(vehicleId);
        alarmSimpleAlarm.setEventType(eventType);
        alarmSimpleAlarm.setAlarmLevel(alarmLevel);
        alarmSimpleAlarm.setAlarmId(Convert.toStr(alarmId));
        alarmSimpleAlarm.setAttachments(attachments);
        alarmSimpleAlarm.setIsDone(false);
        alarmSimpleAlarm.setLongitude(longitude);
        alarmSimpleAlarm.setLatitude(latitude);
        alarmSimpleAlarm.setTime(time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        alarmSimpleAlarm.setTimeConvert(time);
        alarmSimpleAlarm.setNote("");
        alarmSimpleAlarm.setSort(0);
        alarmSimpleAlarm.setIsDel(false);
        alarmSimpleAlarm.setDelTime(LocalDateTime.now());
        alarmSimpleAlarm.setAddTime(LocalDateTime.now());
        alarmSimpleAlarm.setModifyTime(LocalDateTime.now());
        alarmSimpleAlarm.setSysRemark("");
        return alarmSimpleAlarm;
    }


}
